/*******************************************************************************
 * Copyright (c) 2011 Grupo de Sistemas Inteligentes (GSI) - DIT UPM
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *******************************************************************************/
package es.upm.dit.gsi.eclipse.jadex.adfmanager.wizards;


import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.*;
import org.eclipse.jface.operation.*;

import java.io.File;
import java.lang.reflect.InvocationTargetException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.ui.*;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import es.upm.dit.gsi.eclipse.jadex.util.ImageFactory;

/**
 * Wizard for adding a new Goal to the selected agent
 * 
 * It has got 3 pages:
 *  - Page1: Goal details
 *  - Page2: Condition selection
 *  - Page3: Parameters
 *  
 * @author Pablo Muñoz
 */

public class AddGoalWizard extends Wizard implements INewWizard {
	private AddGoalWizardPage1 page1;
	private AddGoalWizardPage2 page2;
	private ParameterSelectionWizardPage page3;
	private ISelection selection;

	/**
	 * Constructor for AddGoalWizard
	 */
	public AddGoalWizard(ISelection selection) {
		super();
		setNeedsProgressMonitor(true);
		this.selection = selection;
		setDefaultPageImageDescriptor(ImageFactory.getImageDescriptor(ImageFactory.GSI_BANNER_SMALL));
	}
	
	/**
	 * Adding pages to the wizard.
	 */
	public void addPages() {
		page1 = new AddGoalWizardPage1(selection);
		page2 = new AddGoalWizardPage2(selection);
		page3 = new ParameterSelectionWizardPage(selection);
		page3.setTitle("Add Goal Wizard");
		addPage(page1);
		addPage(page2);
		addPage(page3);
	}

	/**
	 * This method is called when 'Finish' button is pressed in
	 * the wizard. We will create an operation and run it
	 * using wizard as execution context.
	 */
	public boolean performFinish() {
		final IFile agentFile = (IFile)((IStructuredSelection)selection).getFirstElement();
		//Goal preferences
		final String goalName = page1.getGoalName();
		final String goalType = page1.getGoalType();
		final String retry = page1.getRetry();
		final String retryDelay = page1.getRetryDelay();
		final String exclude = page1.getExclude();
		final String postToAll = page1.getPosttoall();
		final String randomSelection = page1.getRandomSelection();
		final String metalevelReasoning = page1.getMetalevelreasoning();
		final String recur = page1.getRecur();
		final String recurDelay = page1.getRecurDelay();
		
		//Goal conditions
		final String creationConditionLanguage = page2.getCreationConditionLanguage();
		final String creationConditionCode = page2.getCreationConditionCode();
		final String dropConditionLanguage = page2.getDropConditionLanguage();
		final String dropConditionCode = page2.getDropConditionCode();
		final String contextConditionLanguage = page2.getContextConditionLanguage();
		final String contextConditionCode = page2.getContextConditionCode();
		final String recurConditionLanguage = page2.getRecurConditionLanguage();
		final String recurConditionCode = page2.getRecurConditionCode();
		final String maintainConditionLanguage = page2.getMaintainConditionLanguage();
		final String maintainConditionCode = page2.getMaintainConditionCode();
		final String targetConditionLanguage = page2.getTargetConditionLanguage();
		final String targetConditionCode = page2.getTargetConditionCode();
		
		//Goal parameters
		final Parameter[] parameters = page3.getParameters();
		
		//Goal addition
		IRunnableWithProgress op = new IRunnableWithProgress() {
			public void run(IProgressMonitor monitor) throws InvocationTargetException {
				try {
					doFinish(agentFile, goalName, goalType, retry, retryDelay, exclude, 
							postToAll, randomSelection, metalevelReasoning, recur, recurDelay, 
							creationConditionLanguage, creationConditionCode, dropConditionLanguage, 
							dropConditionCode, contextConditionLanguage, contextConditionCode, recurConditionLanguage, 
							recurConditionCode, maintainConditionLanguage, maintainConditionCode, targetConditionLanguage, 
							targetConditionCode, parameters,monitor);
				} catch (CoreException e) {
					throw new InvocationTargetException(e);
				} finally {
					monitor.done();
				}
			}
		};
		
		try {
			getContainer().run(true, false, op);
		} catch (InterruptedException e) {
			return false;
		} catch (InvocationTargetException e) {
			Throwable realException = e.getTargetException();
			MessageDialog.openError(getShell(), "Error", realException.getMessage());
			return false;
		}
		return true;
	}
	
	/**
	 * The worker method. It will add the necessary information to the ADF file in 
	 * order to configure the new Goal.
	 */
	private void doFinish(
			IFile agentFile,
			String goalName,
			String goalType,
			String retry,
			String retryDelay,
			String exclude,
			String postToAll,
			String randomSelection,
			String metalevelReasoning,
			String recur,
			String recurDelay,
			String creationConditionLanguage,
			String creationConditionCode,
			String dropConditionLanguage,
			String dropConditionCode,
			String contextConditionLanguage,
			String contextConditionCode,
			String recurConditionLanguage,
			String recurConditionCode,
			String maintainConditionLanguage,
			String maintainConditionCode,
			String targetConditionLanguage,
			String targetConditionCode,
			Parameter[] parameters,
			IProgressMonitor monitor)
		throws CoreException {
		
		monitor.beginTask("Modificating ADF File", 2);
		
		try{
		DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
		Document doc = docBuilder.parse(agentFile.getRawLocation().toOSString());
	 
		//Get the plans element 
		Node goals = doc.getElementsByTagName("goals").item(0);
		
		Element newGoal = doc.createElement(goalType);
		newGoal.setAttribute("name", goalName);
		
		//Set the BDI Flags for the new goal
		if(retry != null) newGoal.setAttribute("retry", retry);
		if(retryDelay != null) newGoal.setAttribute("retrydelay", retryDelay);
		if(exclude != null) newGoal.setAttribute("exlude", exclude);
		if(postToAll != null) newGoal.setAttribute("posttoall", postToAll);
		if(randomSelection != null) newGoal.setAttribute("randomselection", randomSelection);
		if(metalevelReasoning != null) newGoal.setAttribute("metalevelreasoning", metalevelReasoning);
		if(recur != null) newGoal.setAttribute("recur", recur);
		if(recurDelay != null) newGoal.setAttribute("recurdelay", recurDelay);
		
		//Set the Goal conditions
		if(creationConditionCode != null){
			Element creationCondition = doc.createElement("creationcondition");
			creationCondition.setAttribute("language", creationConditionLanguage);
			creationCondition.setTextContent(creationConditionCode);
			newGoal.appendChild(creationCondition);
		}
		if(dropConditionCode != null){
			Element dropCondition = doc.createElement("dropcondition");
			dropCondition.setAttribute("language", dropConditionLanguage);
			dropCondition.setTextContent(dropConditionCode);
			newGoal.appendChild(dropCondition);
		}
		if(contextConditionCode != null){
			Element contextCondition = doc.createElement("contextcondition");
			contextCondition.setAttribute("language", contextConditionLanguage);
			contextCondition.setTextContent(contextConditionCode);
			newGoal.appendChild(contextCondition);
		}
		if(recurConditionCode != null){
			Element recurCondition = doc.createElement("recurcondition");
			recurCondition.setAttribute("language", recurConditionLanguage);
			recurCondition.setTextContent(recurConditionCode);
			newGoal.appendChild(recurCondition);
		}
		if(maintainConditionCode != null){
			Element maintainCondition = doc.createElement("maintaincondition");
			maintainCondition.setAttribute("language", maintainConditionLanguage);
			maintainCondition.setTextContent(maintainConditionCode);
			newGoal.appendChild(maintainCondition);
		}
		if(targetConditionCode != null){
			Element targetCondition = doc.createElement("targetcondition");
			targetCondition.setAttribute("language", targetConditionLanguage);
			targetCondition.setTextContent(targetConditionCode);
			newGoal.appendChild(targetCondition);
		}
		
		//Set the Goal Parameters
		if(parameters != null){
			for(Parameter p : parameters){
				Element parameter = doc.createElement("parameter");
				parameter.setAttribute("name", p.get_name());
				parameter.setAttribute("class", p.get_class());
				parameter.setAttribute("description", p.get_description());
				parameter.setAttribute("direction",p.get_direction());
				parameter.setAttribute("dynamic", p.get_dynamic());
				parameter.setAttribute("exported",p.get_exported());
				parameter.setAttribute("optional", p.get_optional());
				parameter.setAttribute("transient",p.get_transient());
				parameter.setAttribute("updaterate", p.get_updaterate());
				if(p.get_value().length() > 0){
					Element value = doc.createElement("value");
					value.setTextContent(p.get_value());
					parameter.appendChild(value);
				}
				newGoal.appendChild(parameter);
			}
		}
		goals.appendChild(newGoal);
	 
		//write the content into xml file
	    TransformerFactory transformerFactory = TransformerFactory.newInstance();
	    transformerFactory.setAttribute("indent-number", new Integer(4));
	    Transformer transformer;
		transformer = transformerFactory.newTransformer();
		transformer.setOutputProperty(OutputKeys.INDENT, "yes");
	    DOMSource source = new DOMSource(doc);
	    StreamResult result =  new StreamResult(new File(agentFile.getRawLocation().toOSString()));
	    transformer.transform(source, result);
	    agentFile.refreshLocal(IFile.DEPTH_INFINITE, monitor);
		}
		catch(Exception e1){
			e1.printStackTrace();
		}
	    System.out.println("Done");
		monitor.worked(1);
	}
	
	
	/*
	private void throwCoreException(String message) throws CoreException {
		IStatus status =
			new Status(IStatus.ERROR, "Agent_Editor", IStatus.OK, message, null);
		throw new CoreException(status);
	}
	*/

	/**
	 * We will accept the selection in the workbench to see if
	 * we can initialize from it.
	 * @see IWorkbenchWizard#init(IWorkbench, IStructuredSelection)
	 */
	public void init(IWorkbench workbench, IStructuredSelection selection) {
		this.selection = selection;
	}
}